#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <SDL.h>
#include "racanhack.h"
#include "task.h"
#include "video.h"
#include "cave.h"
#include "player.h"
#include "monster.h"
#include "object.h"
#include "object2.h"
#include "invent.h"
#include "main.h"

enum {
  HOW_SELECT_EQUIP,
  HOW_SELECT_APPLY,
  HOW_SELECT_THROW,
  HOW_SELECT_DROP,
  HOW_SELECT_MAX
};

enum {
  LABEL_OBJECT_MAX_LEN = 32
};

static GtkWidget *which_window;
static GtkWidget *how_window;
static GtkWidget *which_button[INVENTORY_MAX];
static GtkWidget *which_cancel_button;
static GtkWidget *how_button[HOW_SELECT_MAX];
static GtkWidget *how_cancel_button;

static gboolean cancel;
static struct _object *selected_object;
static gint how;

static gint order_object(struct _object *object);
static gint cmp_invent(gconstpointer o0, gconstpointer o1);
static void label_object(gchar *buf, struct _object *object);
static void create_which_window();
static void create_how_window();
static gboolean window_delete_event(GtkWidget *widget, GdkEvent  *event, gpointer data);
static gboolean which_window_key_press_event(GtkWidget *widget, GdkEventKey *event);
static gboolean how_window_key_press_event(GtkWidget *widget, GdkEventKey *event);
static void which_button_clicked(GtkButton *button, gpointer data);
static void how_button_clicked(GtkButton *button, gpointer data);
static void cancel_button_clicked(GtkButton *button, gpointer data);
static void parse();

state player_open_inventory(struct _task *task)
{
  struct _player *player;
  player = (struct _player *)task->pointer[0];
  if (task->count == 0) {
    cancel = FALSE;
    how = 0;
    selected_object = NULL;
    selected_object_apply = NULL;
    create_which_window();
  };
}

static gint order_object(struct _object *object)
{
  if (object == Player.weapon) return 0;
  if (object == Player.shield) return 1;
  if (object == Player.arrow) return 2;
  if (object == Player.ring) return 3;
  return (object->id + 4);
}

static gint cmp_invent(gconstpointer o0, gconstpointer o1)
{
  struct _object *object[2];
  object[0] = (struct _object *)o0; 
  object[1] = (struct _object *)o1;
  if (order_object(object[0]) > order_object(object[1])) return (1);
  if (order_object(object[0]) == order_object(object[1])) return (0);
  if (order_object(object[0]) < order_object(object[1])) return (-1);
  g_assert_not_reached();
  return (0);
}

static void label_object(gchar *buf, struct _object *object)
{
  switch (object_type(object)) {
  case OBJECT_TYPE_WEAPON:
    if (object == Player.weapon) {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s + %d(equipped)", object_name(object), object->plus);
    } else {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s + %d", object_name(object), object->plus);
    };
    break;
  case OBJECT_TYPE_SHIELD:
    if (object == Player.shield) {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s + %d(equipped)", object_name(object), object->plus);
    } else {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s + %d", object_name(object), object->plus);
    };
    break;
  case OBJECT_TYPE_ARROW:
    if (object == Player.arrow) {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s x %d(equipped)", object_name(object), object->count);
    } else {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s x %d", object_name(object), object->count);
    };
    break;
  case OBJECT_TYPE_RING:
    if (object == Player.ring) {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s + %d(equipped)", object_name(object), object->plus);
    } else {
      if (object_ident(object)) {
	g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s + %d", object_name(object), object->plus);
      } else {
	g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s", object_name(object));
      };
    };
    break;
  case OBJECT_TYPE_WAND:
    if (object_ident(object)) {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s x %d", object_name(object), object->count);
    } else {
      g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s", object_name(object));
    };
    break;
  default:
    g_snprintf(buf, LABEL_OBJECT_MAX_LEN, "%s", object_name(object));
    break;
  };
}

static void create_which_window()
{
  GtkWidget *vbutton_box;
  GList *li;
  int i;
  struct _object *object;
  gchar buf[LABEL_OBJECT_MAX_LEN];
  which_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(which_window), "Inventory");
  g_signal_connect(G_OBJECT(which_window), "delete_event", G_CALLBACK(window_delete_event), NULL);
  g_signal_connect(G_OBJECT(which_window), "key_press_event", G_CALLBACK(which_window_key_press_event), NULL);
  gtk_container_set_border_width(GTK_CONTAINER(which_window), 10);

  vbutton_box = gtk_vbutton_box_new();
  gtk_container_add(GTK_CONTAINER(which_window), vbutton_box);

  Player.inventory_list = g_list_sort(Player.inventory_list, cmp_invent);
  for (li = g_list_first(Player.inventory_list), i = 0; li != NULL; li = g_list_next(li), i++) {
    object = (struct _object *)li->data;
    label_object(buf, object);
    which_button[i] = gtk_button_new_with_label(buf);
    g_signal_connect(G_OBJECT(which_button[i]), "clicked", G_CALLBACK(which_button_clicked), object);
    g_signal_connect_swapped(G_OBJECT(which_button[i]), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(which_window));
    gtk_container_add(GTK_CONTAINER(vbutton_box), which_button[i]);
  };
  which_cancel_button = gtk_button_new_with_label("cancel");
  g_signal_connect(G_OBJECT(which_cancel_button), "clicked", G_CALLBACK(cancel_button_clicked), NULL);
  g_signal_connect_swapped(G_OBJECT(which_cancel_button), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(which_window));
  gtk_container_add(GTK_CONTAINER(vbutton_box), which_cancel_button);
  gtk_window_set_modal(GTK_WINDOW(which_window), TRUE);
  gtk_widget_show_all(which_window);
}

static void create_how_window()
{
  GtkWidget *vbutton_box;
  int i;
  char *label;
  int focus;
  how_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(how_window), "Inventory");
  g_signal_connect(G_OBJECT(how_window), "delete_event", G_CALLBACK(window_delete_event), NULL);
  g_signal_connect(G_OBJECT(how_window), "key_press_event", G_CALLBACK(how_window_key_press_event), NULL);
  gtk_container_set_border_width(GTK_CONTAINER(how_window), 10);

  vbutton_box = gtk_vbutton_box_new();
  gtk_container_add(GTK_CONTAINER(how_window), vbutton_box);
  for (i = 0; i < HOW_SELECT_MAX; i++) {
    switch(i) {
    case HOW_SELECT_EQUIP:
      if ((selected_object == Player.weapon) ||
	  (selected_object == Player.shield) ||
	  (selected_object == Player.arrow) ||
	  (selected_object == Player.ring)) {
	label = "take off";
      } else {
	label = "equip";
      };
      break;
    case HOW_SELECT_APPLY:
      label = "apply";
      break;
    case HOW_SELECT_THROW:
      label = "throw";
      break;
    case HOW_SELECT_DROP:
      label = "drop";
      break;
    default:
      g_assert_not_reached();
      break;
    };
    how_button[i] = gtk_button_new_with_label(label);
    g_signal_connect(G_OBJECT(how_button[i]), "clicked", G_CALLBACK(how_button_clicked), GINT_TO_POINTER(i));
    g_signal_connect_swapped(G_OBJECT(how_button[i]), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(how_window));
    gtk_container_add(GTK_CONTAINER(vbutton_box), how_button[i]);
  };
  how_cancel_button = gtk_button_new_with_label("cancel");
  g_signal_connect(G_OBJECT(how_cancel_button), "clicked", G_CALLBACK(cancel_button_clicked), NULL);
  g_signal_connect_swapped(G_OBJECT(how_cancel_button), "clicked", G_CALLBACK(gtk_widget_destroy), G_OBJECT(how_window));
  gtk_container_add(GTK_CONTAINER(vbutton_box), how_cancel_button);

  switch (object_type(selected_object)) {
  case OBJECT_TYPE_WEAPON:
    focus = HOW_SELECT_EQUIP;
    break;
  case OBJECT_TYPE_SHIELD:
    focus = HOW_SELECT_EQUIP;
    break;
  case OBJECT_TYPE_ARROW:
    focus = HOW_SELECT_EQUIP;
    break;
  case OBJECT_TYPE_RING:
    focus = HOW_SELECT_EQUIP;
    break;
  case OBJECT_TYPE_POTION:
    if (selected_object->id == OBJECT_ID_POISON_POTION) {
      if (object_ident(selected_object)) {
	focus = HOW_SELECT_THROW;
	break;
      };
    };
    focus = HOW_SELECT_APPLY;
    break;
  case OBJECT_TYPE_SCROLL:
    focus = HOW_SELECT_APPLY;
    break;
  case OBJECT_TYPE_WAND:
    focus = HOW_SELECT_APPLY;
    break;
  case OBJECT_TYPE_FOOD:
    focus = HOW_SELECT_APPLY;
    break;
  case OBJECT_TYPE_EXTRA:
    focus = HOW_SELECT_APPLY;
    break;
  default:
    g_assert_not_reached();
    break;
  };
  gtk_window_set_focus(GTK_WINDOW(how_window), how_button[focus]);
  gtk_widget_show_all(how_window);
}

static gboolean window_delete_event(GtkWidget *widget, GdkEvent  *event, gpointer data)
{
  return TRUE;
}

static gboolean which_window_key_press_event(GtkWidget *widget, GdkEventKey *event)
{
  guint keyval;
  keyval = gdk_keyval_to_lower(event->keyval);
  switch (keyval) {
  case GDK_f: g_signal_emit_by_name(G_OBJECT(gtk_window_get_focus(GTK_WINDOW(which_window))), "clicked"); break;
  case GDK_j: gtk_widget_child_focus(which_window, GTK_DIR_TAB_FORWARD); break;
  case GDK_k: gtk_widget_child_focus(which_window, GTK_DIR_TAB_BACKWARD); break;
  case GDK_i: g_signal_emit_by_name(G_OBJECT(which_cancel_button), "clicked"); break;
  };
  return TRUE;
}

static gboolean how_window_key_press_event(GtkWidget *widget, GdkEventKey *event)
{
  guint keyval;
  keyval = gdk_keyval_to_lower(event->keyval);
  switch (keyval) {
  case GDK_f: g_signal_emit_by_name(G_OBJECT(gtk_window_get_focus(GTK_WINDOW(how_window))), "clicked"); break;
  case GDK_j: gtk_widget_child_focus(how_window, GTK_DIR_TAB_FORWARD); break;
  case GDK_k: gtk_widget_child_focus(how_window, GTK_DIR_TAB_BACKWARD); break;
  case GDK_i: g_signal_emit_by_name(G_OBJECT(how_cancel_button), "clicked"); break;
  };
  return TRUE;
}

static void which_button_clicked(GtkButton *button, gpointer data)
{
  if (selected_object == NULL) {
    selected_object = (struct _object *)data;
    create_how_window();
  } else {
    selected_object_apply = (struct _object *)data;
    parse();
  };
}

static void how_button_clicked(GtkButton *button, gpointer data)
{
  how = GPOINTER_TO_INT(data);
  parse();
}

static void cancel_button_clicked(GtkButton *button, gpointer data)
{
  cancel = TRUE;
  parse();
}

static void parse()
{
  if (cancel) {
    player_trans_state(player_action_start, &Player);
    return;
  };
  if ((selected_object != NULL) &&
      (selected_object_apply == NULL)) {
    object_move_from_inventory(selected_object);
    switch(how) {
    case HOW_SELECT_EQUIP:
      object_player_trans_state(object_player_equip, selected_object, &Player);
      return;
    case HOW_SELECT_APPLY:
      if ((selected_object->id == OBJECT_ID_IDENT_SCROLL) ||
	  (selected_object->id == OBJECT_ID_RMCURSE_SCROLL)) {
	if (g_list_length(Player.inventory_list) != 0) {
	  msg("choose a target.");
	  create_which_window();
	  return;
	};
      };
      object_player_trans_state(object_player_apply, selected_object, &Player);
      return;
    case HOW_SELECT_THROW:
      object_player_trans_state(object_player_throw, selected_object, &Player);
      return;
    case HOW_SELECT_DROP:
      object_player_trans_state(object_player_drop, selected_object, &Player);
      return;
    };
  };
  if ((selected_object != NULL) &&
      (selected_object_apply != NULL)) {
    object_player_trans_state(object_player_apply, selected_object, &Player);
    return;
  };
  g_assert_not_reached();
}
